/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "interface/i_scanner.h"
#include "mc/debounce/average.h"
#include "mc/debounce/binary_continue.h"
#include "mc/debounce/continue.h"
#include "mc/debounce/median.h"
#include "mc/engine/property.h"
#include <chrono>
#include <thread>

namespace dev {

void IScanner::start_scanner_task() {
    // 如果已经有timer在运行，先停止它
    if (m_scanner_timer) {
        m_scanner_timer->stop();
        m_scanner_timer = nullptr;
    }

    // 验证Period是否已设置
    try {
        auto period = Period.get_value();
        if (period.is_null()) {
            dlog("start_scanner_task failed: Period is null");
            return;
        }

        auto period_ms = period.as<uint32_t>();
        if (period_ms == 0) {
            dlog("start_scanner_task failed: Period is zero");
            return;
        }

        // 创建定时器并启动
        m_scanner_timer = new mc::core::timer(this);
        m_scanner_timer->timeout.connect([this]() {
            update_scanner_task();
        });
        m_scanner_timer->set_single_shot(false);
        m_scanner_timer->start(mc::milliseconds(period_ms));

        dlog("Scanner timer started successfully, period: ${period}ms", ("period", period_ms));
    } catch (const std::exception& e) {
        dlog("start_scanner_task failed: ${error}", ("error", e.what()));
    }
}

void IScanner::stop_scanner_task() {
    if (m_scanner_timer) {
        try {
            m_scanner_timer->stop();
            dlog("Scanner timer stopped successfully");
        } catch (const std::exception& e) {
            dlog("Exception occurred while stopping timer: ${error}", ("error", e.what()));
            m_scanner_timer = nullptr; // 确保指针被清空
        }
    }

    // 停止Scanner后，恢复Value和Status到停止状态
    auto nominal_value = NominalValue.get_value().as<uint64_t>();
    Value.set_value(nominal_value);
    Status.set_value(SCANNER_STOPPED);
}

bool IScanner::init_debounce_config() {
    mc::engine::ref_object* ref_obj = nullptr;
    try {
        auto debounce_value = Debounce.get_value();
        ref_obj             = debounce_value.as<mc::engine::ref_object*>();
    } catch (const std::exception& e) {
        dlog("init_debounce_config failed: Unable to get Debounce object reference ${error}", ("error", e.what()));
        handle_result_failure();
        return false;
    }
    if (ref_obj == nullptr) {
        dlog("init_debounce_config failed: Debounce object reference is invalid");
        handle_result_failure();
        return false;
    }
    auto name = Debounce.get_value().as<std::string>();

    if (name.find("Average") != std::string::npos) {
        auto window_size = ref_obj->get_property("WindowSize").as<uint32_t>();
        auto is_signed   = ref_obj->get_property("IsSigned").as<bool>();
        debounce         = std::make_unique<mc::debounce::Average>(window_size, is_signed);
    } else if (name.find("Median") != std::string::npos) {
        auto window_size = ref_obj->get_property("WindowSize").as<uint32_t>();
        auto is_signed   = ref_obj->get_property("IsSigned").as<bool>();
        debounce         = std::make_unique<mc::debounce::Median>(window_size, is_signed);
    } else if (name.find("Continue") != std::string::npos) {
        auto count = ref_obj->get_property("Count").as<uint32_t>();
        debounce   = std::make_unique<mc::debounce::Continue>(count);
    } else if (name.find("BinaryContinue") != std::string::npos) {
        auto h_count = ref_obj->get_property("HighLevelCount").as<uint32_t>();
        auto l_count = ref_obj->get_property("LowLevelCount").as<uint32_t>();
        debounce     = std::make_unique<mc::debounce::BinaryContinue>(h_count, l_count);
    } else {
        return false;
    }

    return true;
}

void IScanner::handle_result_failure() {
    failure_count++;
    success_count = 0;
    if (failure_count >= FailureDebounceCount.get_value().as<uint8_t>()) {
        Status.set_value(SCANNER_FAILURE);
    }
    else {
        Status.set_value(SCANNER_PRE_FAILURE);
    }
}

void IScanner::handle_result_success(uint64_t value) {
    success_count++;
    // 当前为失败状态，且成功计数小于成功防抖计数，则跳过
    if (failure_count >= FailureDebounceCount.get_value().as<uint8_t>() && 
        success_count < SuccessDebounceCount.get_value().as<uint8_t>()) {
        ilog("no enough success count, skip");
        return;
    }
    failure_count = 0;
    Status.set_value(SCANNER_OK);
    Value.set_value(value);
}

void IScanner::update_scanner_task() {
    try {
        // 获取属性值
        auto chip_value         = Chip.get_value();
        auto offset_value       = Offset.get_value();
        auto size_value         = Size.get_value();
        auto type_value         = Type.get_value();
        auto scan_enabled_value = ScanEnabled.get_value();
        if (scan_enabled_value.as<uint8_t>() == 0) {
            dlog("update_scanner_task: ScanEnabled is 0, skip update");
            return;
        }

        // 验证属性值
        if (chip_value.is_null()) {
            dlog("update_scanner_task failed: Chip is null");
            handle_result_failure();
            return;
        }

        if (offset_value.is_null() || size_value.is_null() || type_value.is_null()) {
            dlog("update_scanner_task failed: Offset, Size or Type is null");
            handle_result_failure();
            return;
        }

        if (Debounce.get_property_type_value() ==
                static_cast<uint32_t>(mc::engine::p_type::ref_object) &&
            debounce == nullptr && init_debounce_config() == false) {
            handle_result_failure();
            return;
        }

        // 从引用获取对象
        mc::engine::ref_object* ref_obj = nullptr;
        try {
            ref_obj = chip_value.as<mc::engine::ref_object*>();
        } catch (const std::exception& e) {
            dlog("update_scanner_task failed: Unable to get Chip object reference ${error}", ("error", e.what()));
            handle_result_failure();
            return;
        }

        if (ref_obj == nullptr) {
            dlog("update_scanner_task failed: Chip object reference is invalid");
            handle_result_failure();
            return;
        }

        // 根据Type参数决定调用BitIORead还是BlockIORead
        uint8_t  type  = type_value.as<uint8_t>();
        uint64_t value = 0;

        if (type == 0) {
            // 使用BitIORead方法，参数为offset, size, mask
            auto mask_value = Mask.get_value();
            if (mask_value.is_null()) {
                dlog("update_scanner_task failed: Mask is null for BitIORead");
                handle_result_failure();
                return;
            }

            mc::variants args = {offset_value, size_value, mask_value};
            mc::variant  result;
            try {
                result = ref_obj->invoke("BitIORead", args);
            } catch (const std::exception& e) {
                dlog("update_scanner_task failed: BitIORead call failed ${error}", ("error", e.what()));
                handle_result_failure();
                return;
            }

            // 安全地提取数据
            if (result.is_null()) {
                dlog("update_scanner_task failed: BitIORead returned null");
                handle_result_failure();
                return;
            }

            try {
                std::vector<uint8_t> read_data = result.as<std::vector<uint8_t>>();
                if (read_data.empty()) {
                    MC_THROW(mc::invalid_op_exception, "BitIORead returned empty data");
                }

                uint32_t             mask_value   = 0;
                uint32_t             current_byte = 0;
                std::vector<uint8_t> byte_read_buf(4, 0);

                size_t size = std::min(read_data.size(), sizeof(uint64_t));

                const uint32_t mask = Mask.get_value().as<uint32_t>();

                for (uint32_t i = 0; i < 8 * size; i++) {
                    if ((mask >> i) & 0x01) {
                        current_byte = read_data[size - (i / 8) - 1];
                        byte_read_buf[mask_value / 8] |=
                            (((current_byte >> (i % 8)) & 0x01) << (mask_value % 8));
                        mask_value++;
                    }
                }

                const size_t final_size = std::min(byte_read_buf.size(), sizeof(uint64_t));
                for (size_t i = 0; i < final_size; ++i) {
                    value |= (static_cast<uint64_t>(byte_read_buf[i]) << (i * 8));
                }
            } catch (const std::exception& e) {
                dlog("update_scanner_task failed: BitIORead data conversion failed ${error}",
                     ("error", e.what()));
                handle_result_failure();
                return;
            }
        } else {
            // 使用BlockIORead方法，参数为offset, size
            mc::variants args = {offset_value, size_value};
            mc::variant  result;
            try {
                result = ref_obj->invoke("BlockIORead", args);
            } catch (const std::exception& e) {
                dlog("update_scanner_task failed: BlockIORead call failed ${error}",
                     ("error", e.what()));
                handle_result_failure();
                return;
            }

            // 安全地提取数据
            if (result.is_null()) {
                dlog("update_scanner_task failed: BlockIORead returned null");
                handle_result_failure();
                return;
            }

            std::vector<uint8_t> read_data;
            try {
                read_data = result.as<std::vector<uint8_t>>();
            } catch (const std::exception& e) {
                dlog("update_scanner_task failed: BlockIORead data conversion failed ${error}",
                     ("error", e.what()));
                handle_result_failure();
                return;
            }

            if (read_data.empty()) {
                dlog("update_scanner_task failed: Read data is empty");
                handle_result_failure();
                return;
            }

            size_t size = std::min(read_data.size(), sizeof(uint64_t));
            for (size_t i = 0; i < size; ++i) {
                value |= (static_cast<uint64_t>(read_data[i]) << (i * 8));
            }
        }

        if (debounce) {
            std::optional<int> dbl_val = debounce->get_debounce_val(value);
            if (!dbl_val) {
                handle_result_failure();
                return;
            }
            dlog("Scanner debounce value obtained successfully: original value=${value} debounced value=${value1}",
                 ("value", value)("value1", *dbl_val));
            value = *dbl_val;
        }

        auto scan_enabled = ScanEnabled.get_value().as<uint8_t>();
        if (scan_enabled == 1) {
            handle_result_success(value);
        }

        dlog("Scanner read successfully: value=${value}", ("value", value));

    } catch (const std::exception& e) {
        dlog("update_scanner_task exception: ${error}", ("error", e.what()));
        handle_result_failure();
    }
}

void IScanner::init_scanner_signal() {
    try {
        auto scan_enabled_value = ScanEnabled.get_value();
        if (scan_enabled_value.as<uint8_t>() == 0) {
            Status.set_value(SCANNER_STOPPED);
            auto nominal_value = NominalValue.get_value().as<uint64_t>();
            Value.set_value(nominal_value);
            
        }
    } catch (const std::exception& e) {
        elog("failed to init scanner enabled signal: ${error}", ("error", e.what()));
    }
    try {
        auto& signal = ScanEnabled.property_changed();
        signal.connect([this](const mc::variant& value, const auto& prop) {
            if (value.as<uint8_t>() == 1) {
                start_scanner_task();
            } else {
                stop_scanner_task();
            }
        });
    } catch (const std::exception& e) {
        elog("Signal connection establishment failed: ${error}", ("error", e.what()));
    }
}

} // namespace dev

MC_REFLECT(dev::IScanner)
